/**
 * 
 */
package com.cipe.cmrs.controllers.payment;

import java.sql.Timestamp;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.support.SessionStatus;
import org.springframework.web.servlet.ModelAndView;

import com.cipe.cmrs.bean.CodeDescriptionBean;
import com.cipe.cmrs.bean.PaymentRequestBean;
import com.cipe.cmrs.controllers.BaseController;
import com.cipe.cmrs.converter.DateEditor;
import com.cipe.cmrs.filter.SessionObjectFilter;
import com.cipe.cmrs.model.Country;
import com.cipe.cmrs.model.Payee;
import com.cipe.cmrs.model.Paymenttype;
import com.cipe.cmrs.model.Projectreport;
import com.cipe.cmrs.model.User;
import com.cipe.cmrs.model.view.ProjectPaymentView;
import com.cipe.cmrs.service.AccountCodeService;
import com.cipe.cmrs.service.CipeprojectService;
import com.cipe.cmrs.service.CountryService;
import com.cipe.cmrs.service.PayeeService;
import com.cipe.cmrs.service.PaymentrequestService;
import com.cipe.cmrs.service.PaymenttypeService;
import com.cipe.cmrs.service.ProjectReportService;
import com.cipe.cmrs.service.UserService;
import com.cipe.cmrs.util.Constants;
import com.cipe.cmrs.util.CustomTimestampEditor;
import com.cipe.cmrs.util.NumberUtil;

/**
 * @author Incepio
 * 
 */
public abstract class AbstractPaymentController extends BaseController {
    /**
	 * 
	 */
    private static final long serialVersionUID = 2071110718678373348L;
    protected static final String COMMAND_NAME = "paymentrequest";
    @Autowired
    protected PaymentrequestService paymentrequestService;
    @Autowired
    protected CountryService countryService;
    @Autowired
    protected PaymenttypeService paymenttypeService;
    @Autowired
    protected UserService userService;
    @Autowired
    protected PayeeService payeeService;
    @Autowired
    protected CipeprojectService cipeprojectService;
    @Autowired
    protected ProjectReportService projectReportService;
    @Autowired
    protected AccountCodeService accountCodeService;

    @InitBinder
    public void initBinder(WebDataBinder binder) {
		super.initBinder(binder);
    }

    @RequestMapping(method = RequestMethod.GET)
    protected ModelAndView getFormView(@ModelAttribute(COMMAND_NAME) PaymentRequestBean bean, HttpServletRequest request) {
        ModelAndView mav = new ModelAndView(getFormView());
        PaymentRequestBean unsavedPayment = (PaymentRequestBean) request.getSession().getAttribute(SessionObjectFilter.UNSAVED_PAYMENT);
        if (unsavedPayment != null) {
            bean = unsavedPayment;
            mav.addObject(COMMAND_NAME, bean);
        }

        String payeeIdParam = (String) request.getParameter("payeeId");
        if (StringUtils.hasText(payeeIdParam) && NumberUtil.INSTANCE.isInteger(payeeIdParam)) {
            Integer payeeId = Integer.valueOf(payeeIdParam);
            if (payeeId > 0) {
                bean.setPayeeId(payeeId);
            }
        }
        return mav.addAllObjects(getReferenceData(bean, request));
    }

    protected ModelAndView getSuccessView(PaymentRequestBean paymentRequest, HttpServletRequest request) {
        return new ModelAndView(getSuccessView()).addAllObjects(getReferenceData(paymentRequest, request));
    }

    protected abstract ModelAndView onSubmit(@ModelAttribute(COMMAND_NAME) PaymentRequestBean bean, BindingResult result,
        HttpServletRequest request, SessionStatus status);

    protected Map<String, Object> getReferenceData(PaymentRequestBean paymentRequest, HttpServletRequest request) {
        Map<String, Object> map = new HashMap<String, Object>();

        // The line items should only appear when the request is initially opened,
        // but after the FA selects the "Receive in Finance" button
        // the line items should no longer appear on subsequent screens.
        boolean showPaymentLineItems = false;
        if (this instanceof AddPaymentController || this instanceof EditPaymentRequestController
        		|| this instanceof ProcessPaymentController
        		&& (getText("status.payment.process.new").equalsIgnoreCase(paymentRequest.getStatusCode())
        				|| getText("status.payment.process.resubmitted").equalsIgnoreCase(paymentRequest.getStatusCode())
        				|| getText("status.payment.process.finance").equalsIgnoreCase(paymentRequest.getStatusCode()))) {
        	showPaymentLineItems = true;
        }
        map.put("showPaymentLineItems", showPaymentLineItems);

        if (showPaymentLineItems) map.put("cipeProjects", getAllCipeProjects(paymentRequest.getId()));
        if (showPaymentLineItems) map.put("accountCodes", getAllAccountCodes());
        map.put("currentUserId", getUserId(request));
        map.put("countryList", getAllCountries());
        map.put("userList", getAllUsers());
        //map.put("payeeList", getAllPayees(paymentRequest));
        Paymenttype paymenttype = paymenttypeService.findByPaymenttypename(Constants.PartnerPaymentType);
        if (paymentRequest.getPaymentTypeId() != null && paymentRequest.getPaymentTypeId().equals(paymenttype.getId())) {
        	map.put("payeeList", getPayeesByType(paymentRequest, Constants.PartnerPayeeType));
        } else {
        	map.put("payeeList", getAllPayees(paymentRequest));
        }
        map.put("paymenttypeList", getActivePaymentTypes(paymentRequest));

        // When user runs the "Partner Payment Form" report, he should be notified:
        // 1) if receipt of any of the associated Narrative or Financial report is overdue
        // or has not yet been forwarded to the grants department
        boolean showPrintPartnerPaymentRequestFormMessage = false;
        if (paymentRequest.getId() != null && paymentRequest.getId() > 0) {
        	List<Projectreport> projectReports = projectReportService.findProjectReportsByPaymentRequestId(paymentRequest.getId());
        	if(projectReports != null && !projectReports.isEmpty()) {
        		for(Projectreport report : projectReports) {
        			if(Constants.NARRATIVE_TYPE.equals(report.getType())
        					|| Constants.FINANCIAL_TYPE.equals(report.getType())) {
        	            Date currentDate = new Date();
        				if (report.getReportdue() != null && currentDate.after(report.getReportdue())
        						|| report.getReporttogrants() != null && currentDate.after(report.getReporttogrants())) {
        					showPrintPartnerPaymentRequestFormMessage = true;
        				}
        			}
        		}
        	}
        }
        map.put("showPrintPartnerPaymentRequestFormMessage", showPrintPartnerPaymentRequestFormMessage);
        return map;
    }

    public List<ProjectPaymentView> getAllCipeProjects(Integer excludePaymentRequest) {
        return cipeprojectService.getAllActiveCipeProjects(excludePaymentRequest);
    }

    public List<CodeDescriptionBean> getAllAccountCodes() {
        return accountCodeService.getAllAccountCodeBeans(Arrays.asList("id", "accountCode", "description", "accountStatus"));
    }

    public Integer getUserId(HttpServletRequest request) {
        return getUserId(request.getSession());
    }

    public List<Country> getAllCountries() {
        return countryService.getAllCountries();
    }

    public List<Paymenttype> getActivePaymentTypes(PaymentRequestBean bean) {
        return paymenttypeService.getActivePaymentTypes(bean.getPaymentTypeId());
    }

    public List<User> getAllUsers() {
        return userService.findAll();
    }

    public List<Payee> getAllPayees(PaymentRequestBean paymentRequest) {
        return payeeService.getAllActivePayees(paymentRequest.getPayeeId());
    }

    public List<Payee> getPayeesByType(PaymentRequestBean paymentRequest, String payeetype) {
        return payeeService.getActivePayeesByType(paymentRequest.getPayeeId(), payeetype);
    }

}
